﻿using System;
using System.Collections.Specialized;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using VitCode.BaseDataPageCreator.Setting;
using VitCode.Castle.DataAccess;

namespace VitCode.BaseDataPageCreator
{
    /// <summary>
    /// PageSaveHelper 的摘要說明。
    /// </summary>
    public class PageSaveHelper
    {
        protected PageLoadHelper m_LoadHelper;
        protected Page m_Page;
        protected PageBuilder m_PageBuilder;
        protected PageRuleHelper m_RuleHelper;
        protected ObjXmlReader m_XmlReader;

        public PageSaveHelper(Page page, string settingXmlPath)
        {
            m_Page = page;
            m_RuleHelper = new PageRuleHelper(settingXmlPath);
            m_LoadHelper = new PageLoadHelper(settingXmlPath);
            m_XmlReader = new ObjXmlReader(settingXmlPath);
            m_PageBuilder = new PageBuilder(m_Page, settingXmlPath);
        }

        public string GetNodeAttributeValue(XmlNode proNode, string attName, bool isIgnore)
        {
            return m_XmlReader.GetNodeAttributeValue(proNode, attName, isIgnore);
        }

        public object CloneObject(object srcObj, string idProName, bool isWithId)
        {
            object reVal = null;

            if (srcObj != null)
            {

                var objType = srcObj.GetType();
                reVal = Activator.CreateInstance(objType);
                var srcPs = objType.GetProperties();
                foreach (var p in srcPs)
                {
                    if (isWithId)
                    {
                        var proVal = p.GetValue(srcObj, null);
                        p.SetValue(reVal, proVal, null);
                    }
                }
            }

            return reVal;
        }

        private string GetCtlKeyValue(Control ctl)
        {
            if (ctl.GetType() == typeof (TextBox))
                return ((TextBox) ctl).Text;
            return "";
        }


        

        public void SetObjectPropetyValue(object obj, XmlNode proNode, BaseDataAccess acc)
        {
            SetObjectPropetyValue(obj, proNode, acc, null);
        }

        public void SetObjectPropetyValue(object obj, XmlNode proNode, BaseDataAccess acc, UserControl uc)
        {
            try
            {
                if (proNode.Attributes.Count == 0)
                    return;
                string strLgnoreSave = GetNodeAttributeValue(proNode, m_LoadHelper.LGNORE_SAVE, true);
                string strClassName = GetNodeAttributeValue(proNode, m_LoadHelper.CLASS_NAME, true);
                string strCtlObjKeyPro = GetNodeAttributeValue(proNode, m_LoadHelper.CTL_OBJ_KEY_PAO, true);
                if (strLgnoreSave.ToLower() == "true")
                    return;
                string strName = m_LoadHelper.OBJ_PRO_HEAD_STRING +
                                 GetNodeAttributeValue(proNode, m_LoadHelper.NAME, false);
                PropertyInfo pi = m_LoadHelper.GetProperty(proNode, obj.GetType());
                Control ctl;
                object proValue = null;
                if (uc == null)
                    ctl = m_Page.FindControl(strName);
                else
                    ctl = uc.FindControl(strName);
                if (ctl == null)
                    return;

                if (strClassName.Length > 0)
                {
                    if (strCtlObjKeyPro.Length == 0)
                    {
                        throw new ArgumentException("在設置ClassName的同時,請設置CtlObjKeyPro屬性");
                    }
                    else
                    {
                        string strProObjKeyProVal = m_LoadHelper.GetProObjStringValue(strCtlObjKeyPro, ctl);
                        string strProObjKyeProName = m_LoadHelper.GetClassKeyPropertyName(strClassName);
                        proValue = m_PageBuilder.GetObjectByHql(strClassName, strProObjKyeProName, strProObjKeyProVal,
                                                                acc.Session);
                        if (pi.CanWrite)
                            pi.SetValue(obj, proValue, null);
                        return;
                    }
                }
                else if (ctl.GetType() == typeof (TextBox))
                {
                    string strText = ((TextBox) ctl).Text;
                    if (pi.PropertyType == typeof(DateTime))
                    {
                        try
                        {
                          proValue = Convert.ToDateTime(strText);
                        }
                        catch (Exception)
                        {
                            
                            throw new ArgumentException("日期格式不正確！");
                        }
                        
                    }
                    else if (pi.PropertyType == typeof(Int32) || pi.PropertyType == typeof(Double) || pi.PropertyType == typeof(float))
                    {
                        string strVal = ((TextBox)ctl).Text;
                        try
                        {
                             if(strVal.IndexOf('%') > 0)
                            {
                                var value = strVal.Substring(0, strVal.Length - 1);
                                strVal = (Convert.ToDouble(value) / 100).ToString();
                                proValue = Convert.ChangeType(strVal, pi.PropertyType); 
                            }
                            else
                            {
                                if (strVal.Length > 0)
                                proValue = Convert.ChangeType(strVal,pi.PropertyType); 
                            }
                        }
                        catch (Exception)
                        {
                            
                            throw new ArgumentException("必須為數位！");
                        }
                      
                        
                    }
                    else
                        proValue = ((TextBox)ctl).Text;
                }
                else if (ctl.GetType() == typeof (CheckBox))
                    proValue = ((CheckBox) ctl).Checked;
                else
                {
                    string ctlProNameForObj = m_XmlReader.GetNodeAttributeValue(proNode,
                                                                                m_LoadHelper.CTL_PROPERTY_FRO_OBJCET,
                                                                                true);
                    if (ctlProNameForObj.Length == 0)
                        ctlProNameForObj = "Text";
                    PropertyInfo piKeyHeadString = ctl.GetType().GetProperty("KeyHeadString");
                    if (piKeyHeadString != null)
                    {
                        if (obj != null)
                        {
                            PropertyInfo piObjCode = obj.GetType().GetProperty("Code");
                            if (piObjCode != null)
                                piKeyHeadString.SetValue(ctl, piObjCode.GetValue(obj, null), null);
                        }
                    }
                    PropertyInfo ctlTextPro = ctl.GetType().GetProperty(ctlProNameForObj);

                    if (ctlTextPro != null)
                    {
                        proValue = ctlTextPro.GetValue(ctl, null);
                    }
                }
                if (proValue == null)
                    pi.SetValue(obj, null, null);
                else
                {
                    if (pi.PropertyType == typeof (Int32) && !CreateControlHelper.CheckIsInt(proValue.ToString()))
                        return;
                    if (pi.CanWrite)
                    {
                        var proType = pi.PropertyType;
                        var tempType = Nullable.GetUnderlyingType(proType);
                        if (tempType != null)//解決DateTime? 泛型指向
                        {
                            proType = tempType;
                        }
                        pi.SetValue(obj, Convert.ChangeType(proValue, proType), null);
                    }
                }
            }
            catch (Exception ex)
            {
                m_XmlReader.ShowErrorSettingInfo(proNode, ex);
            }
        }

        public object SavePageObject(string className, string typeName, string keyValue,
                                     out StringCollection scObjErrMsg)
        {
            return SavePageObject(className, typeName, keyValue,
                                  out scObjErrMsg,true,true);
        }

        public object GetPageObject(string className, string typeName, string keyValue, BaseDataAccess acc)
        {
            bool isAdd = false;
            return GetPageObject(className, typeName, keyValue, acc, out isAdd);
        }
        public object GetPageObject(string className, string typeName, string keyValue, BaseDataAccess acc, out bool isAdd)
        {
            object obj;
            PageLoadHelper settingHelper = m_LoadHelper;
            string strKeyField = settingHelper.SetObjectKeyField(className);
            
            isAdd = true;
            Type objType = m_LoadHelper.GetClassTypeByClassNodeName(className);
            if (string.IsNullOrEmpty(keyValue))
                obj = Activator.CreateInstance(objType);
                
            else
            {
                obj = m_PageBuilder.GetObjectByHql(className, strKeyField, keyValue, acc.Session);
                isAdd = false;
            }
            XmlNodeList proList = m_LoadHelper.GetProNodesFromXML(className, typeName);

            if (typeName.Length > 0)
            {
                PropertyInfo pi = objType.GetProperty(m_LoadHelper.TYPE_NAME);
                if (pi != null)
                    pi.SetValue(obj, typeName, null);
            }
            foreach (XmlNode node in proList)
                SetObjectPropetyValue(obj, node, acc);
            return obj;
        }

        public object GetPageObject(object obj,string typeName, BaseDataAccess acc)
        {
            if(obj!=null)
            {
                var objType = obj.GetType();
                XmlNodeList proList = m_LoadHelper.GetProNodesFromXML(objType.Name, typeName);

                if (!string.IsNullOrEmpty(typeName))
                {
                    PropertyInfo pi = objType.GetProperty(m_LoadHelper.TYPE_NAME);
                    if (pi != null)
                        pi.SetValue(obj, typeName, null);
                }
                foreach (XmlNode node in proList)
                    SetObjectPropetyValue(obj, node, acc);
            }
            return obj;
        }

        public virtual object SavePageObject(Object obj,
                                     out StringCollection scObjErrMsg, bool isTrans, bool isAdd, BaseDataAccess acc)
        {
            if (isTrans)
                acc.BeginTransaction();
            try
            {
                string strClassName = obj.GetType().Name;
                string strClassMemo = m_XmlReader.GetNodeAttributeValue(strClassName, m_LoadHelper.MEMO, true);
                string strKeyField = m_LoadHelper.SetObjectKeyField(strClassName);
                scObjErrMsg = new StringCollection();
                m_RuleHelper.AccSession = acc.Session;
                string strHisMemo = strClassMemo + "頁面新增";
                m_RuleHelper.CheckObjectSaveDBRules(obj, out scObjErrMsg);
                if (isAdd)
                {
                    if (scObjErrMsg.Count == 0)
                        acc.Add(obj);
                    else
                        return null;
                }
                else
                {
                    strHisMemo = strClassMemo + "頁面更新";
                    if (scObjErrMsg.Count == 0)
                        acc.Update(obj);
                    else
                        return null;
                }
                if (isTrans)
                    acc.Commit();
            }
            catch (Exception ex)
            {
                if (isTrans)
                    acc.RollBack();
                throw;
            }
            finally
            {
                if (isTrans)
                    acc.CloseSession();
            }
            return obj;
        }

        public virtual object SavePageObject(string className, string typeName, string keyValue,
                                     out StringCollection scObjErrMsg, bool isTrans, bool isHistory)
        {
            object obj;
            var acc = new BaseDataAccess();
            //var hisAcc = new HistoryAccess();
            //hisAcc.Session = acc.Session;
            if(isTrans)
                acc.BeginTransaction();
            try
            {
                string strClassMemo = m_XmlReader.GetNodeAttributeValue(className, m_LoadHelper.MEMO, true);
                string strKeyField = m_LoadHelper.SetObjectKeyField(className);
                bool isAdd = true;
                scObjErrMsg = new StringCollection();
                obj = GetPageObject(className, typeName, keyValue, acc, out isAdd);
                
                m_RuleHelper.AccSession = acc.Session;
                string strHisMemo = strClassMemo + "頁面新增";
                m_RuleHelper.CheckObjectSaveDBRules(obj, out scObjErrMsg);
                if (isAdd)
                {
                    if (scObjErrMsg.Count == 0)
                         acc.Add(obj);
                    else
                        return null;
                }
                else
                {
                    strHisMemo = strClassMemo + "頁面更新";
                    if (scObjErrMsg.Count == 0)
                        acc.Update(obj);
                    else
                        return null;
                }
                //if(isHistory)
                //{
                //    MethodInfo mi = obj.GetType().GetMethod(BaseHistoryEntity.GET_HISTORY_OBJECT_TYPE);
                //    if (mi != null)
                //    {
                //        object miReVal = mi.Invoke(obj, null);
                //        if (miReVal != null && miReVal is Type)
                //            hisAcc.SaveHisRecord(obj, (Type)miReVal, strKeyField, strHisMemo);
                //    }
                //}

                if (isTrans)
                    acc.Commit();
            }
            //catch (Exception ex)
            //{
            //    if (isTrans)
            //    {
            //        scObjErrMsg = new StringCollection { "某些值必須為數字類型，請檢測！" };
            //        acc.RollBack();
            //        return null;
            //    }
            //    throw;

            //}
            finally
            {
                if(isTrans)
                    acc.CloseSession();
            }
            return obj;
        }

      
    }
}
